library(jazzPanda)
library(SpatialExperiment)
library(Seurat)
library(ggplot2)
library(data.table)
library(dplyr)
library(glmnet)
library(caret)
library(ComplexUpset)
library(ggrepel)
library(gridExtra)
library(patchwork)
library(RColorBrewer)
library(limma)
library(here)
library(tidyr)
library(xtable)
source(here("scripts/utils.R"))

load the data

rep1=get_xenium_data(path="/stornext/Bioinf/data/lab_phipson/data/xenium_Mm_brain/xenium_prerelease_jun20_mBrain_replicates/mBrain_ff_rep1/", 
              mtx_name = "cell_feature_matrix_mtx/")

rep2=get_xenium_data(path="/stornext/Bioinf/data/lab_phipson/data/xenium_Mm_brain/xenium_prerelease_jun20_mBrain_replicates/mBrain_ff_rep2/", 
              mtx_name = "cell_feature_matrix_mtx/")

rep3=get_xenium_data(path="/stornext/Bioinf/data/lab_phipson/data/xenium_Mm_brain/xenium_prerelease_jun20_mBrain_replicates/mBrain_ff_rep3/", 
              mtx_name = "cell_feature_matrix_mtx/")

rep1$trans_info = rep1$trans_info[rep1$trans_info$qv >=20 & rep1$trans_info$cell_id != -1 & !(rep1$trans_info$cell_id %in% rep1$zero_cells), ]
rep2$trans_info = rep2$trans_info[rep2$trans_info$qv >=20 &  rep2$trans_info$cell_id != -1 & !(rep2$trans_info$cell_id %in% rep2$zero_cells), ]
rep3$trans_info = rep3$trans_info[rep3$trans_info$qv >=20 & rep3$trans_info$cell_id != -1 & !(rep3$trans_info$cell_id %in% rep3$zero_cells), ]

data_nm  <- "xenium_mbrain"
# load geenrated data
cluster_info = readRDS(here(data_path,paste0(data_nm, "_clusters.Rds")))
anno_df <- data.frame(
  cluster = c("c0","c1","c2","c3","c4","c5","c6","c7","c8","c9"),
  major_class = c("Glia",
                  "Neuron (Glut)",
                  "Neuron (Glut)",
                  "Neuron (GABA)",
                  "Non-neuronal",
                  "Neuron (Glut)",
                  "Neuron (Glut)",
                  "Neuron (Glut)",
                  "Immune",
                  "Neuron (Glut)"),
  subclass = c("OL lineage / Astrocytes",
               "IT (intratelencephalic)",
               "Projection (CT)",
               "Interneuron",
               "Vascular / Stromal",
               "Hippocampal excitatory",
               "Hippocampal excitatory",
               "PT (subcortical-projecting)",
               "Microglia",
               "IT"),
  anno_name = c("Astro-OPC/OL mix",
                "IT L2/3-4",
                "CT-like L6",
                "Pvalb interneuron",
                "Vascular/ChP fibro-endo",
                "CA pyramidal",
                "DG granule",
                "PT L5",
                "Microglia",
                "IT Hpcal1"),
  Notes = c("Diffuse background, mix of astrocytic (Gfap) and oligodendrocytic (Opalin, Sox10) signals",
            "Strong superficial cortical band, Cux1/2, Satb2, Rorb",
            "Deep cortical band, Foxp2, Slc17a6, Nell1",
            "Sparse across cortex, Gad1/2, Pvalb, Syt2",
            "Strands and CP region, Igf2, Pecam1, Col1a1",
            "CA1–CA3 band, Slc17a7, Car4, Neurod6",
            "Clear DG granule cell layer, Prox1, Calb1",
            "Deep cortical stripe, Bcl11b, Penk",
            "Scattered puncta, Trem2, Cd68, Siglech",
            "Edge-localized cluster, Hpcal1, Cdh4"),
  stringsAsFactors = FALSE
)


cluster_info = merge(cluster_info, anno_df, by="cluster")
cluster_names = paste0("c",0:9 )
cluster_info$cluster = factor(cluster_info$cluster,
                              levels=cluster_names)
# cluster_info = cluster_info[order(cluster_info$cluster), ]

cluster_info$anno_name = factor(cluster_info$anno_name,
                              levels=anno_df$anno_name)
cluster_info = cluster_info[order(cluster_info$anno_name), ]


jazzPanda_res_lst = readRDS(here(data_path,paste0(data_nm, "_jazzPanda_res_lst.Rds")))
fit.cont = readRDS(here(data_path,paste0(data_nm, "_fit_cont_obj.Rds")))
FM_result= readRDS(here(data_path,paste0(data_nm, "_seu_markers.Rds")))
sv_lst = readRDS(here(data_path,paste0(data_nm, "_sq20_vector_lst.Rds")))
seu = readRDS(here(data_path,paste0(data_nm, "_seu.Rds")))

Idents(seu)=cluster_info$anno_name[match(colnames(seu), cluster_info$cells)]
seu$sample = cluster_info$sample[match(colnames(seu), cluster_info$cells)]

Dataset overview

plot_data_sp(cluster_info=cluster_info,file_prefix = data_nm, 
             my_colors = my_colors, ct_nm = "anno_name")
png 
  2 
plot_cluster_props(cluster_info=cluster_info,file_prefix = data_nm, 
                   my_colors = my_colors, ct_nm = "anno_name")
png 
  2 
plot_umap_seu(cluster_info=cluster_info,seu=seu, file_prefix = data_nm, 
              my_colors = my_colors, ct_nm = "anno_name",fig_w = 3000)
png 
  2 

Spatial pattern of negative controls

nc_sp1 <- rep1$trans_info[rep1$trans_info$feature_name %in% c(rep1$probe, rep1$codeword),
                                c("x", "y", "feature_name")]
nc_sp2 <- rep2$trans_info[rep2$trans_info$feature_name %in% c(rep2$probe, rep2$codeword), 
                                c("x", "y", "feature_name")]
nc_sp3 <- rep3$trans_info[rep3$trans_info$feature_name %in% c(rep3$probe, rep3$codeword), 
                                c("x", "y", "feature_name")]
nc_coords = as.data.frame(rbind(cbind(nc_sp1, sample= "replicate1"), 
                                cbind(nc_sp2, sample= "replicate2"),
                                cbind(nc_sp2, sample= "replicate3"))
                          )
nc_coords$category = "negative control probe"
nc_coords[nc_coords$feature_name %in% c(rep1$codeword,rep2$codeword,rep3$codeword), "category"] = "negative control codeword"
cat("#negative controls", length(unique((nc_coords$feature_name))), "\n")
#negative controls 81 
nc_coords$category=factor(nc_coords$category, 
                          levels =c("negative control probe",
                                   "negative control codeword"))

jpeg(file.path(overview_PA, paste0(data_nm, "_nc_xy.jpg")), 
     width=600*2, height=800*3, res=200)
ggplot(nc_coords, aes(x=x, y=y))+
    geom_point(size=0.01, color="black")+
    theme_bw()+
    facet_wrap(category~sample)+
    scale_y_reverse()+
    defined_theme+
    theme(strip.text = element_text(size=8), 
          strip.background = element_rect(fill =NA,colour = "black"))
dev.off()
png 
  2 

jazzPanda-glm

jazzPanda_res = get_top_mg(jazzPanda_res_lst, coef_cutoff=0.1)  
jazzPanda_summary = as.data.frame(table(jazzPanda_res$top_cluster))
colnames(jazzPanda_summary) = c("cluster","jazzPanda_glm")
# Combine into a new dataframe for LaTeX output
output_data <- do.call(rbind, lapply(cluster_names, function(cl) {
  subset <- jazzPanda_res[jazzPanda_res$top_cluster == cl, ]
  sorted_subset <- subset[order(-subset$glm_coef), ]
  gene_list <- paste(sorted_subset$gene, "(", round(sorted_subset$glm_coef, 2), ")", sep="", collapse=", ")
 
  return(data.frame(Cluster = cl, Genes = gene_list))
}))

latex_table <- xtable(output_data, caption="Detected marker genes for each cluster by jazzPanda, in decreasing value of glm coefficients")
print.xtable(latex_table, include.rownames = FALSE, hline.after = c(-1, 0, nrow(output_data)), comment = FALSE)

top3 marker genes by jazzPanda-glm

xr <- c(0, 3000)
yr <- c(0, 4135)
plot_lst=list()
for (cl in paste("c", 0:9, sep="")){
    ct_nm = anno_df[anno_df$cluster==cl, "anno_name"]
    inters=jazzPanda_res[jazzPanda_res$top_cluster==cl,"gene"]
    rounded_val=signif(as.numeric(jazzPanda_res[inters,"glm_coef"]),
                          digits = 3)
    inters_df = as.data.frame(cbind(gene=inters, value=rounded_val))
    inters_df$value = as.numeric(inters_df$value)
    inters_df=inters_df[order(inters_df$value, decreasing = TRUE),]
    inters_df$text= paste(inters_df$gene,inters_df$value,sep=": ")
    
    if (length(inters > 0)){
        inters_df = inters_df[1:min(3, nrow(inters_df)),]
        inters = inters_df$gene
        all_trans = as.data.frame(matrix(0, ncol=6))
        colnames(all_trans) = c("x","y", "feature_name","value","text_label","sample")
        for (rp in c("rep1","rep2","rep3")){
          rp_lst = get(rp)
          iters_sp1= rp_lst$trans_info$feature_name %in% inters
          vis_r1 =rp_lst$trans_info[iters_sp1,
                            c("x","y","feature_name")]
          vis_r1$value = inters_df[match(vis_r1$feature_name,inters_df$gene),
                            "value"]
          vis_r1=vis_r1[order(vis_r1$value,decreasing = TRUE),]
          vis_r1$text_label= paste(vis_r1$feature_name,
                                vis_r1$value,sep=": ")
          vis_r1$text_label=factor(vis_r1$text_label, levels=inters_df$text)
          vis_r1$sample=paste("replicate", substr(rp,start = 4, stop=4),sep="")
          all_trans = rbind(all_trans,vis_r1)
        }
        all_trans = all_trans[2:nrow(all_trans),]
        all_trans$text_label = factor(all_trans$text_label, 
                                      levels = inters_df$text)
        all_trans = all_trans[order(all_trans$text_label),]

        genes_plt<- ggplot(data = all_trans,
                    aes(x = x, y = y))+ 
                    #geom_point(size=0.0001)+
                    geom_hex(bins = auto_hex_bin(mean(table(all_trans$sample, 
                                                            all_trans$feature_name))))+
                    facet_grid(sample~text_label)+
                    scale_x_reverse() +
                    scale_fill_gradient(low="white", high="maroon4") + 
                    #scale_color_manual(values = c("maroon4","maroon4","maroon4"))+
                    guides(fill = guide_colorbar(barheight = unit(0.2, "npc"), 
                                                 barwidth  = unit(0.03, "npc")))+
                    defined_theme+ theme(legend.position = "right", 
                              strip.background = element_rect(fill =NA,colour = NA),
                              strip.text = element_text(size = rel(1.2)), 
                              strip.text.y.right = element_blank(),
                              legend.key.width = unit(2, "cm"),
                              legend.title = element_text(size = 10),
                              legend.text = element_text(size = 10),
                               legend.key.height = unit(2, "cm"))
        
        cluster_data =  cluster_info[cluster_info$cluster==cl, ]
        cluster_data$label = paste(cluster_data$sample, cluster_data$anno_name, sep="-")
        cluster_data$label =factor(cluster_data$label, 
                                   levels=paste(paste("replicate",1:3,sep=""),
                                                ct_nm,sep="-"))
        p_cl<- ggplot(data =cluster_data,
                    aes(x = x, y = y, color=sample))+ 
                    #geom_hex(bins = 100)+
                    geom_point(size=0.01)+
                    facet_wrap(~label, nrow=3,strip.position = "left")+
                    scale_x_reverse() +
                    scale_color_manual(values = c("black","black","black"))+
                    #scale_fill_gradient(low="white", high="maroon4") + 
                    #guides(fill = guide_colorbar(barwidth = unit(15, "cm"),height= unit(30, "cm")))+
                    defined_theme + theme(legend.position = "none", 
                              strip.background = element_blank(), legend.key.width = unit(15, "cm"),
                              strip.text = element_text(size = rel(1.2)))

        lyt <-p_cl | genes_plt
        layout_design <- lyt + patchwork::plot_layout(heights = c(1,1),widths = c(1, 3)) 
        plot_lst[[cl]] = print(layout_design)
        cat("cluster:", cl,"\n")
        jpeg(file.path(mg_PA,paste0(data_nm, "_glm_", cl,"_top3.jpg")),
             width=600*4, height=800*3, res=200)
        print(layout_design)
        dev.off()
    }
  }
cluster: c0 
cluster: c1 
cluster: c2 
cluster: c3 
cluster: c4 
cluster: c5 
cluster: c6 
cluster: c7 
cluster: c8 
cluster: c9 

## cluster vector versus marker gene vector

plot_lst=list()
nbins = 400
for (cl in cluster_names){
    ct_nm = anno_df[anno_df$cluster==cl, "anno_name"]
    inters_df=jazzPanda_res[jazzPanda_res$top_cluster==cl,]

    inters_df=inters_df[order(inters_df$glm_coef, decreasing = TRUE),]
    
    inters_df = inters_df[1:min(3, nrow(inters_df)),]
    mk_genes = inters_df$gene

    dff = as.data.frame(cbind(sv_lst$cluster_mt[,cl],
                              sv_lst$gene_mt[,mk_genes]))
    colnames(dff) = c("cluster", mk_genes)
    dff$sample= "replicate1"
    dff[400:800,"sample"] = "replicate2"
    dff[800:1200,"sample"] = "replicate3"
    dff$vector_id = c(1:400, 1:400, 1:400)
    long_df <- dff %>% 
    pivot_longer(cols = -c(cluster, sample, vector_id), names_to = "gene", 
               values_to = "vector_count")
    long_df$gene = factor(long_df$gene, levels=mk_genes)
    long_df$sample = factor(long_df$sample , 
                        levels=c("replicate1","replicate2", "replicate3"))
    p<-ggplot(long_df, aes(x = cluster, y = vector_count, color=gene )) +
    geom_point(size=0.01) +
    facet_grid(sample~gene, scales="free_y") +
    labs(x = paste(ct_nm, " cluster vector ", sep=""), 
         y = "Top3 marker gene vector") +
    theme_minimal()+
        scale_y_continuous(expand = c(0.01,0.01))+ 
        scale_x_continuous(expand =  c(0.01,0.01))+ 
        theme(panel.grid = element_blank(),legend.position = "none",
        strip.text = element_text(size = 12),
        axis.line=element_blank(),
        axis.text=element_text(size = 11),
        axis.ticks=element_line(color="black"),
        axis.title=element_text(size = 13),
        panel.border  =element_rect(colour = "black", 
                                    fill=NA, linewidth=0.5)
        )
    plot_lst[[cl]] = p
}


n_per_page <- 6
rem <- length(plot_lst) %% n_per_page
if (rem != 0) {
  n_pad <- n_per_page - rem
  plot_lst <- c(
    plot_lst,
    rep(list(patchwork::plot_spacer()), n_pad)
  )
}

# Split into 2×2 pages
plot_chunks <- split(plot_lst, ceiling(seq_along(plot_lst) / n_per_page))

pdf(file.path(mg_PA, paste0(data_nm, "_glm_mg_vvplot.pdf")),
    height = 12, width = 12)

for (chunk in plot_chunks) {
  # arrange 2 columns, auto rows
   p <- wrap_plots(chunk, ncol = 2) +
       plot_layout(heights = c(1,1,1), widths = c(1,1))
  print(p)
}

dev.off()
png 
  2 

Compare marker genes by different methods

FindMarker and limma result

table(FM_result$cluster)

FM_result$cluster <- factor(FM_result$cluster, levels = paste0("c", 0:9))

top_mg <- FM_result %>%
  group_by(cluster) %>%
  arrange(desc(avg_log2FC), .by_group = TRUE) %>% 
  slice_max(order_by = avg_log2FC, n = 10) %>%
  select(cluster, gene, avg_log2FC)
uni_clusters <-paste0("c", 0:9)

# Combine into a new dataframe for LaTeX output
output_data <- do.call(rbind, lapply(uni_clusters, function(cl) {
  subset <- top_mg[top_mg$cluster == cl, ]
  sorted_subset <- subset[order(-subset$avg_log2FC), ]
  gene_list <- paste(sorted_subset$gene, "(", round(sorted_subset$avg_log2FC, 2), ")", sep="", collapse=", ")
 
  return(data.frame(Cluster = cl, Genes = gene_list))
}))

latex_table <- xtable(output_data, caption="Detected marker genes for each cluster by FindMarkers")
print.xtable(latex_table, include.rownames = FALSE, hline.after = c(-1, 0, nrow(output_data)), comment = FALSE)
limma_dt <- decideTests(fit.cont)
summary(limma_dt)
        c0  c1  c2  c3  c4  c5  c6  c7  c8  c9
Down   201 120 155 132 189 171 212 207 176 158
NotSig   4  20  10  14  11  15   3   5  38  35
Up      79 144 119 138  84  98  69  72  70  91

Cumulative rank plot

plot_lst=list()
cor_M = cor(sv_lst$gene_mt,
            sv_lst$cluster_mt[, paste0("c", 0:9)],
            method = "spearman")
cor_M[cor_M <= 0.5] = 0
cor_M[cor_M > 0.5]=1
Idents(seu)=cluster_info$cluster[match(colnames(seu), cluster_info$cells)]
for (cl in paste("c", 0:9, sep="")){
    ct_nm = anno_df[anno_df$cluster==cl, "anno_name"]
    fm_cl=FindMarkers(seu, ident.1 = cl, only.pos = TRUE,
            logfc.threshold = 0.25)
    fm_cl = fm_cl[order(fm_cl$avg_log2FC, decreasing = TRUE),]
    to_plot =row.names(fm_cl)
    FM_pt = data.frame("name"=to_plot,"rk"= 1:length(to_plot),
                   "y"= cumsum(cor_M[to_plot, cl]),
                   "type"="FindMarkers")
    
    limma_cl<-topTable(fit.cont,coef=cl,p.value = 0.05, n=Inf, sort.by = "p")
    limma_cl = limma_cl[limma_cl$logFC>0, ]
    to_plot_lm = row.names(limma_cl)
    
    
    lasso_sig = jazzPanda_res[jazzPanda_res$top_cluster==cl,]
    lasso_sig = lasso_sig[order(lasso_sig$glm_coef, decreasing = TRUE),]
    
    limma_pt = data.frame("name"=to_plot_lm,"rk"= 1:length(to_plot_lm),
                   "y"= cumsum(cor_M[to_plot_lm, cl]),
                   "type"="limma")
    
    lasso_pt = data.frame("name"=lasso_sig$gene,"rk"= 1:nrow(lasso_sig),
                   "y"= cumsum(cor_M[lasso_sig$gene, cl]),
                   "type"="jazzPanda-glm")
  
    data_lst = rbind(limma_pt, lasso_pt,FM_pt)
    data_lst$type <- factor(data_lst$type,
            levels = c("limma", "FindMarkers", "jazzPanda-glm"),
            labels = c("limma", "Wilcoxon Rank Sum Test", "jazzPanda-glm")
    )
    data_lst$rk = as.numeric(data_lst$rk)
    p <-ggplot(data_lst, aes(x = rk, y = y, color = type)) +
        geom_step(size = 0.8) +  # type = "s"
        scale_color_manual(values = c("limma" = "black",
                                    "Wilcoxon Rank Sum Test" = "blue",
                                    "jazzPanda-glm" = "red")) +
        labs(title = ct_nm, x = "Rank of marker genes",
             y = "Cumulative count of genes with correlation >0.5",
             color = NULL) +
        theme_classic(base_size = 12) +
        theme(plot.title = element_text(hjust = 0.5),
            axis.line = element_blank(),  
            panel.border = element_rect(color = "black", 
                                        fill = NA, linewidth = 1),
            legend.position = "inside",
            legend.position.inside = c(0.98, 0.02),
            legend.justification = c("right", "bottom"),
            legend.background = element_rect(color = "black", 
                                             fill = "white", linewidth = 0.5),
            legend.box.background = element_rect(color = "black",
                                                 linewidth = 0.5)
        )
    plot_lst[[cl]] <- p
}

combined_plot <- wrap_plots(plot_lst, ncol = 3)
pdf(file.path(comp_PA, paste0(data_nm, "_mg_compare_rank.pdf")),
    height = 20, width = 15)
combined_plot 
dev.off()
png 
  2 

upset plot

plot_lst=list()
for (cl in paste("c", 0:9, sep="")){
    ct_nm = anno_df[anno_df$cluster==cl, "anno_name"]
    findM_sig <- FM_result[FM_result$cluster==cl,"gene"]
    limma_sig <- row.names(limma_dt[limma_dt[,cl]==1,])
    lasso_cl <- jazzPanda_res[jazzPanda_res$top_cluster==cl, "gene"]
    df_mt <- as.data.frame(matrix(FALSE,nrow=nrow(jazzPanda_res),ncol=3))
    row.names(df_mt) <- jazzPanda_res$gene
    colnames(df_mt) <- c("jazzPanda-glm",
                      "Wilcoxon Rank Sum Test","limma")
    df_mt[findM_sig,"Wilcoxon Rank Sum Test"] <- TRUE
    df_mt[limma_sig,"limma"] <- TRUE
    df_mt[lasso_cl,"jazzPanda-glm"] <- TRUE
    
    df_mt$gene_name <- row.names(df_mt)
    
    p<-upset(df_mt,
              intersect=c("limma","Wilcoxon Rank Sum Test","jazzPanda-glm"),
              wrap=TRUE, keep_empty_groups= TRUE, name="",
              themes=theme_grey(),
              stripes=upset_stripes(geom=geom_segment(size=5),colors=c( 'grey95', 'grey95','grey95')),
              sort_intersections_by ="cardinality", sort_sets= FALSE,min_degree=1,
              set_sizes=FALSE,
               sort_intersections= "descending", warn_when_converting=FALSE,
               warn_when_dropping_groups=TRUE,encode_sets=TRUE,
              matrix=(intersection_matrix()+
                  theme(axis.text.x=element_blank(),panel.background = element_rect(fill="NA"),
                                          axis.ticks = element_blank(),
                                          axis.title = element_blank())),
               base_annotations=list('Intersection size'=(intersection_size(bar_number_threshold=1,color='grey9',fill='grey80')+
                  scale_y_continuous(expand = expansion(mult = c(0, 0.15)))+
                theme(axis.text.x = element_blank(),axis.title.x = element_blank(),
                      panel.background = element_rect(fill="NA"),
                      panel.grid = element_line(color="grey90"),
                      axis.ticks.x = element_blank()))),
              width_ratio=0.5, height_ratio=1/4)+
           ggtitle(ct_nm)
         
        plot_lst[[cl]] <- p 
}


combined_plot <- wrap_plots(plot_lst, ncol = 4)
pdf(file.path(comp_PA, paste0(data_nm, "_mg_compare_upset.pdf")),
     height =4* (ceiling(length(cluster_names)/4)), width = 16)
combined_plot 
dev.off()
png 
  2 
sessionInfo()
R version 4.5.0 (2025-04-11)
Platform: x86_64-pc-linux-gnu
Running under: Red Hat Enterprise Linux 9.3 (Plow)

Matrix products: default
BLAS:   /stornext/System/data/software/rhel/9/base/tools/R/4.5.0/lib64/R/lib/libRblas.so 
LAPACK: /stornext/System/data/software/rhel/9/base/tools/R/4.5.0/lib64/R/lib/libRlapack.so;  LAPACK version 3.12.1

locale:
 [1] LC_CTYPE=en_AU.UTF-8       LC_NUMERIC=C              
 [3] LC_TIME=en_AU.UTF-8        LC_COLLATE=en_AU.UTF-8    
 [5] LC_MONETARY=en_AU.UTF-8    LC_MESSAGES=en_AU.UTF-8   
 [7] LC_PAPER=en_AU.UTF-8       LC_NAME=C                 
 [9] LC_ADDRESS=C               LC_TELEPHONE=C            
[11] LC_MEASUREMENT=en_AU.UTF-8 LC_IDENTIFICATION=C       

time zone: Australia/Melbourne
tzcode source: system (glibc)

attached base packages:
[1] stats4    stats     graphics  grDevices utils     datasets  methods  
[8] base     

other attached packages:
 [1] xtable_1.8-4                tidyr_1.3.1                
 [3] here_1.0.1                  limma_3.64.1               
 [5] RColorBrewer_1.1-3          patchwork_1.3.1            
 [7] gridExtra_2.3               ggrepel_0.9.6              
 [9] ComplexUpset_1.3.3          caret_7.0-1                
[11] lattice_0.22-6              glmnet_4.1-10              
[13] Matrix_1.7-3                dplyr_1.1.4                
[15] data.table_1.17.8           ggplot2_3.5.2              
[17] Seurat_5.3.0                SeuratObject_5.1.0         
[19] sp_2.2-0                    SpatialExperiment_1.18.1   
[21] SingleCellExperiment_1.30.1 SummarizedExperiment_1.38.1
[23] Biobase_2.68.0              GenomicRanges_1.60.0       
[25] GenomeInfoDb_1.44.2         IRanges_2.42.0             
[27] S4Vectors_0.46.0            BiocGenerics_0.54.0        
[29] generics_0.1.4              MatrixGenerics_1.20.0      
[31] matrixStats_1.5.0           jazzPanda_0.2.4            

loaded via a namespace (and not attached):
  [1] RcppAnnoy_0.0.22        splines_4.5.0           later_1.4.2            
  [4] R.oo_1.27.1             tibble_3.3.0            polyclip_1.10-7        
  [7] hardhat_1.4.2           pROC_1.19.0.1           rpart_4.1.24           
 [10] fastDummies_1.7.5       lifecycle_1.0.4         rprojroot_2.1.0        
 [13] globals_0.18.0          MASS_7.3-65             magrittr_2.0.3         
 [16] plotly_4.11.0           sass_0.4.10             rmarkdown_2.29         
 [19] jquerylib_0.1.4         yaml_2.3.10             httpuv_1.6.16          
 [22] sctransform_0.4.2       spam_2.11-1             spatstat.sparse_3.1-0  
 [25] reticulate_1.43.0       cowplot_1.2.0           pbapply_1.7-4          
 [28] lubridate_1.9.4         abind_1.4-8             Rtsne_0.17             
 [31] presto_1.0.0            purrr_1.1.0             R.utils_2.13.0         
 [34] BumpyMatrix_1.16.0      nnet_7.3-20             ipred_0.9-15           
 [37] lava_1.8.1              GenomeInfoDbData_1.2.14 irlba_2.3.5.1          
 [40] listenv_0.9.1           spatstat.utils_3.1-5    goftest_1.2-3          
 [43] RSpectra_0.16-2         spatstat.random_3.4-1   fitdistrplus_1.2-4     
 [46] parallelly_1.45.1       codetools_0.2-20        DelayedArray_0.34.1    
 [49] tidyselect_1.2.1        shape_1.4.6.1           UCSC.utils_1.4.0       
 [52] farver_2.1.2            spatstat.explore_3.5-2  jsonlite_2.0.0         
 [55] progressr_0.15.1        ggridges_0.5.6          survival_3.8-3         
 [58] iterators_1.0.14        foreach_1.5.2           tools_4.5.0            
 [61] ica_1.0-3               Rcpp_1.1.0              glue_1.8.0             
 [64] prodlim_2025.04.28      SparseArray_1.8.1       xfun_0.52              
 [67] withr_3.0.2             fastmap_1.2.0           digest_0.6.37          
 [70] timechange_0.3.0        R6_2.6.1                mime_0.13              
 [73] colorspace_2.1-1        scattermore_1.2         tensor_1.5.1           
 [76] spatstat.data_3.1-8     R.methodsS3_1.8.2       hexbin_1.28.5          
 [79] recipes_1.3.1           class_7.3-23            httr_1.4.7             
 [82] htmlwidgets_1.6.4       S4Arrays_1.8.1          uwot_0.2.3             
 [85] ModelMetrics_1.2.2.2    pkgconfig_2.0.3         gtable_0.3.6           
 [88] timeDate_4041.110       lmtest_0.9-40           XVector_0.48.0         
 [91] htmltools_0.5.8.1       dotCall64_1.2           scales_1.4.0           
 [94] png_0.1-8               gower_1.0.2             spatstat.univar_3.1-4  
 [97] knitr_1.50              reshape2_1.4.4          rjson_0.2.23           
[100] nlme_3.1-168            cachem_1.1.0            zoo_1.8-14             
[103] stringr_1.5.1           KernSmooth_2.23-26      parallel_4.5.0         
[106] miniUI_0.1.2            pillar_1.11.0           grid_4.5.0             
[109] vctrs_0.6.5             RANN_2.6.2              promises_1.3.3         
[112] cluster_2.1.8.1         evaluate_1.0.4          magick_2.8.7           
[115] cli_3.6.5               compiler_4.5.0          rlang_1.1.6            
[118] crayon_1.5.3            future.apply_1.20.0     labeling_0.4.3         
[121] plyr_1.8.9              stringi_1.8.7           viridisLite_0.4.2      
[124] deldir_2.0-4            BiocParallel_1.42.1     lazyeval_0.2.2         
[127] spatstat.geom_3.5-0     RcppHNSW_0.6.0          future_1.67.0          
[130] statmod_1.5.0           shiny_1.11.1            ROCR_1.0-11            
[133] igraph_2.1.4            bslib_0.9.0